Skip to content

fix(gmail): fix self-reply detection in +reply and +reply-all#685

Open
malob wants to merge 1 commit intogoogleworkspace:mainfrom
malob:fix/reply-self-sent
Open

fix(gmail): fix self-reply detection in +reply and +reply-all#685
malob wants to merge 1 commit intogoogleworkspace:mainfrom
malob:fix/reply-self-sent

Conversation

@malob
Copy link
Copy Markdown
Contributor

@malob malob commented Apr 7, 2026

Description

Fixes self-reply detection for both +reply and +reply-all. When replying to a message sent by the same account, the reply was addressed back to the sender instead of to the original recipients.

The problem

PR #530 added self-reply detection to +reply-all, but it had two gaps:

  1. +reply had no self-reply detection at all. Replying to a self-sent message addressed the reply to the From address (yourself) instead of the original To recipients.

  2. +reply-all only checked two addresses — the primary email (via /users/me/profile) and the resolved --from alias. Any other configured send-as alias was missed, so replying to a message sent from a non-default alias also went to the sender instead of the original recipients.

How it was found

+reply on a real email thread to reply to a self-sent message. The reply was addressed to the sender instead of to the original recipient. Had to be manually re-sent with the correct address.

The fix

The full send-as identity list is now used for self-reply detection, matching Gmail web's behavior:

  • SelfEmails newtype — pre-lowercased set of the user's email addresses, constructed from sendAs identities filtered by Gmail's treatAsAlias setting. The default identity is always included (Workspace accounts have treatAsAlias: false on the primary, but it is still "self"). Non-default, non-alias addresses (e.g. external send-as) are excluded.

  • Single sendAs fetchhandle_reply calls fetch_send_as_identities once and shares the result between resolve_sender_with_identities (From resolution + display name enrichment) and SelfEmails::from_identities (self-reply detection + self-exclusion). No duplicate API calls.

  • build_reply_recipients — new function for plain +reply, parallel to build_reply_all_recipients. Detects self-reply and uses original To recipients with no self-exclusion (Gmail's "follow-up" behavior, per Google's documentation and community expert confirmation).

  • Graceful degradation — if the sendAs fetch fails for +reply, self-reply detection is disabled with a warning but the reply still works. For +reply-all, it is a hard error since incorrect self-exclusion would produce wrong recipients.

What changed

  • SelfEmails newtype in mod.rs with from_identities, empty, contains_email, iter
  • SendAsIdentity gains treat_as_alias field (parsed from Gmail API's treatAsAlias)
  • resolve_sender_with_identities extracted from resolve_sender for pre-fetched identity sharing
  • is_self_reply, build_reply_recipients, collect_excluded_emails, build_reply_all_recipients refactored to use &SelfEmails
  • fetch_user_email removed (replaced by sendAs identity list)
  • resolve_sender doc comment updated; resolve_sender_from_identities stays private

Verified with real email

Tested against the actual message that triggered the bug:

To Result
Installed (broken) (yourself) Reply addressed to sender instead of original recipients
Fixed build (original recipient) Reply correctly addressed to the person originally written to

Test coverage

717 total tests (17 new, net +15 after removing fetch_user_email tests). New tests cover:

  • is_self_reply (5): primary match, alias match, case insensitivity, non-match, empty set fallback
  • build_reply_recipients (10): self-reply ignoring Reply-To, normal reply using Reply-To, preserve all To including self (no self-exclusion), note-to-self, alias detection, BCC-only fallback to From, extra CC passthrough, graceful degradation with/without Reply-To
  • SelfEmails (1): treatAsAlias filtering with realistic Workspace data (primary treatAsAlias: false still included)
  • build_reply_all_recipients (1): BCC-only self-sent produces empty To (documents asymmetry with plain reply)

Note on merge conflicts

This PR and #684 (display name fallback) both touch the People API display name enrichment code in mod.rs. This PR extracts it into resolve_sender_with_identities; #684 changes the endpoint from People API to OAuth userinfo. Whichever merges second will need a straightforward rebase to apply the endpoint change in its new location.

Checklist:

  • Code follows the AGENTS.md guidelines (no generated google-* crates).
  • cargo fmt --all applied.
  • cargo clippy -- -D warnings resolved all warnings.
  • Tests prove the fix is effective.
  • Changeset file provided.

When replying to a message you sent, +reply addressed the reply back
to yourself instead of the original recipients. The self-reply
detection from PR googleworkspace#530 only covered +reply-all and only checked the
primary email and resolved alias, missing other send-as identities.

Use the full send-as identity list (filtered by treatAsAlias, with
the default identity always included) for both self-reply detection
and self-exclusion. Fetch identities once and share between sender
resolution (resolve_sender_with_identities) and the new SelfEmails
type used by is_self_reply and collect_excluded_emails.

Plain +reply degrades gracefully if the sendAs fetch fails;
+reply-all hard-fails since incorrect self-exclusion would produce
wrong recipients. Gmail's self-reply preserves original To verbatim
(follow-up behavior, no self-exclusion).
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 7, 2026

🦋 Changeset detected

Latest commit: 831cced

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@googleworkspace/cli Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@googleworkspace-bot googleworkspace-bot added the area: core Core CLI parsing, commands, error handling, utilities label Apr 7, 2026
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses issues with self-reply detection in the Gmail CLI tool. Previously, self-reply detection was limited or missing, leading to replies being incorrectly addressed to the sender instead of the original recipients. The changes introduce a more comprehensive approach to identifying the user's own email addresses, including all send-as aliases, and ensure this information is consistently used to determine correct reply recipients.

Highlights

  • Self-reply detection: Implemented robust self-reply detection for both +reply and +reply-all by utilizing the full list of send-as identities, respecting Gmail's treatAsAlias setting.
  • Identity management: Introduced SelfEmails newtype to manage user identities and refactored handle_reply to fetch send-as identities once, sharing them across sender resolution and self-reply logic.
  • API and logic updates: Added build_reply_recipients for plain +reply to mirror Gmail's follow-up behavior and updated build_reply_all_recipients to use the new identity-based exclusion logic.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Generative AI Prohibited Use Policy, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request improves self-reply detection for Gmail +reply and +reply-all commands by utilizing all send-as identities and respecting the "treat as alias" setting. It refactors identity fetching to reduce API calls and introduces a SelfEmails helper for consistent email comparison. Feedback suggests sanitizing error messages before terminal output to prevent potential escape sequence injection.

Comment on lines +65 to +73
Err(e) => {
crate::output::warn(&format!(
"Could not fetch send-as identities ({}). If this is a \
reply to your own message, the reply may be addressed \
to you instead of the original recipients.",
e
));
vec![]
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

The error string e should be sanitized before being printed to the terminal to prevent escape sequence injection. This is a security best practice for terminal output.

Suggested change
Err(e) => {
crate::output::warn(&format!(
"Could not fetch send-as identities ({}). If this is a \
reply to your own message, the reply may be addressed \
to you instead of the original recipients.",
e
));
vec![]
}
Err(e) => {
crate::output::warn(&format!(
"Could not fetch send-as identities ({}). If this is a \
reply to your own message, the reply may be addressed \
to you instead of the original recipients.",
crate::output::sanitize_for_terminal(&e.to_string())
));
vec![]
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

crate::output::warn() already calls sanitize_for_terminal on its entire input (output.rs line 79), so the error string is sanitized before reaching the terminal. Adding an explicit sanitize_for_terminal here would double-sanitize.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: core Core CLI parsing, commands, error handling, utilities

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants